第三章 数码管的显示原理及实现 |
您所在的位置:网站首页 › uchar num › 第三章 数码管的显示原理及实现 |
第三章 数码管的显示原理及实现
实验板上用了2片74HC573来驱动数码管,分别控制位选和段选信号。 让第一个数码管显示一个8字,代码如图1所示。
图1 数码管显示8 让6个数码管同时点亮,间隔0.5s,依次显示0-F。 #include #define uchar unsigned char #define uint unsigned int sbit wela=P2^6; sbit dula=P2^7; uchar num; uchar code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint);
void main() { wela=1; // turn on u2 latch P0=0xc0; // 6 bits on wela=0; // turn off u2 latch while(1) { for(num=0;num0;i++) for(j=110;j>0;j++); } 难点在于,位选只需要打开一次,就被锁存了,也就是这里的6的数码管都一直被选中了,然后用段选在6个数码管上同时显示0-f。这也是用74573锁存器的好处。 数码管动态显示。每个数码管依次显示不同的数字。 #include #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; sbit wela=P2^7; uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint);
void main() { while(1) { dula=1; //seg1 display P0=table[1]; dula=0; P0=0xff; wela=1; P0=0xfe; wela=0; delayms(500);
dula=1; P0=table[2]; dula=0; P0=0xff; wela=1; P0=0xfd; wela=0; delayms(500);
dula=1; P0=table[3]; dula=0; P0=0xfb; wela=1; P0=0xfe; wela=0; delayms(500);
dula=1; P0=table[4]; dula=0; P0=0xff; wela=1; P0=0xf7; wela=0; delayms(500);
dula=1; P0=table[5]; dula=0; P0=0xff; wela=1; P0=0xef; wela=0; delayms(500);
dula=1; P0=table[6]; dula=0; P0=0xff; wela=1; P0=0xdf; wela=0; delayms(500); } }
void delayms(uint xms) { uint i,j; for(i=xms;i>0;i--) for(j=110;j>0;j--); } 这段代码依次控制6个数码管先锁存段选,再取消,然后锁存位选,再延时。其中,P0=0xff,是为了消隐。可以尝试把延时分别调至100ms,10ms,1ms,可以看到数码管可以越来越稳定的显示1-6,就像6个数码管同时显示一样。这就是动态显示效果。所谓动态显示,即轮流向各位数码管送出字形码和相应的位选,利用发光管的余晖和视觉暂留作用,使人觉得数码管好像在同时显示,而实际上是多位数码管一位一位显示,只是轮流的速度非常快,人眼已无法分辨出来。 中断概念 52单片机共有6个中断源: INT0:外部中断0,由P3.2口引入,低电平或下降沿引起; INT1:外部中断1,由P3.3口引入,低电平或下降沿引起; T0:定时器/计数器0中断,由T0计数器计满回0引起; T1:定时器/计数器1中断,由T1计数器计满回0引起; T2:定时器/计数器2中断,由T2计数器计满回0引起; TI/RI:串口中断,串口完成一帧字符发送/接收后引起。 单片机使用时,通常需要设置两个与中断有关的寄存器:中断允许寄存器IE和中断优先级寄存器IP。 中断允许寄存器: EA:全局中断允许位,1开,0关; ET2:定时器2/计数器2中断允许位; ES:串口中断允许位; ET1:定时器1/计数器1中断允许位; EX1:外部中断1中断允许位; ET0:定时器0/计数器0中断允许位; EX0:外部中断0中断允许位。 中断优先级寄存器IP: PS:串口中断优先级控制位,1高优先级;0低优先级; PT1:定时器/计数器1中断优先级控制位; PX1:外部中断1中断优先级控制位; PT0:定时器/计数器0中断优先级控制位; PX0:外部中断0中断优先级控制位。
3.5 定时器中断 定时器/计数器的实质是加1计数器,由高8位和低8位两个寄存器组成。TMOD是其工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0,T1的启动,停止及设置溢出标志。 加1计数器输入的计数脉冲有两个来源,一个是由系统的时钟振荡器输出脉冲经12分频后送来;另一个是由T0或T1引脚输入的外部脉冲源。每来一个脉冲,计数器加1,当加到计数器全为1时,再输入一个脉冲,就使计数器回零,且计数器的溢出,使TCON寄存器的TF0或TF1置1,向CPU发出中断请求(定时器/计数器中断允许时)。如果定时器/计数器工作于定时模式,则表示定时时间已到。如果工作于计数模式,则表示计数已满。 由此可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。 设置为定时器模式时,加1计数器是对内部机器周期计数(1个机器周期等于12个振荡周期,即计数频率为晶振频率的1/12)。计数值N乘以机器周期Tcy就是定时时间t。 设置为计数器模式时,外部事件计数脉冲由T0或T1引脚输入到计数器。在每个机器周期的S5P2期间采样T0、T1引脚电平。当某周期采样到一高电平输入,下一周期又采样到一低电平时,则计数器加1。更新的计数值在下一机器周期S3P1期间装入计数器。由于检测一个从1-0下降沿需要2个机器周期,因此要求被采样的电平至少要维持一个机器周期。当晶振频率为12M时,最高计数频率不超过1/2M,即计数脉冲周期要大于2us。 TMOD的高4位用于设置定时器1,低4位用于设置定时器0。 GATE-门控制位; GATE=0,定时器/计数器的启动、停止仅受TCON中的TRX控制。 GATE=1,定时器/计数器的启动、停止受TRX和外部中断引脚INT0,INT1上的电平共同控制。 C/T:0-计数器模式;1-定时器模式; M1M0:工作方式选择位。00-13位定时器/计数器;01-16位定时器/计数器;10-8位初值自动重装的8位定时器/计数器;11-仅适用于T0,分成两个8位计数器,T1停止计数。 TCON用来控制启停,标志溢出和中断情况。 TF1-定时器1溢出标志位。当定时器1计满溢出时,由硬件使TF1置1,并申请中断。进入中断服务程序后,由硬件自动清0. TR1-定时器1运行控制位。 TF0-定时器0溢出标志位。 TR0-定制器0运行控制位。 IE1-外部中断1请求标志。 IT1-外部中断1触发方式选择。 IE0- IT0- 定时器初值的计算方法:当用定时器方式1时,设机器周期为Tcy,定时器产生一次中断的时间为t,那么需要计数的个数N=t/Tcy,装入THX和TLX中的数分别为 THX=(65536-N)/256; TLX=(65536-N)%256; 在写单片机定时器程序时,在程序开始处需要对定时器及中断寄存器做初始化设置,通常定时器初始化过程如下: 对TMOD赋值,以确定T0和T1的工作方式; 计算初值,并将初值写入TH1,TL1或TH0,TL0; 中断方式时,对IE赋值,开放中断; 使TR0,TR1置位,启动定时器/计数器定时或计数。
//发光管以1秒间隔闪烁 #include #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; uchar num; void main() { TMOD=0x01; //设置定时器0为工作方式1(M1M0为01) TH0=(65536-45872)/256; //装初值11.0592M晶振定时50ms数为45872 TL0=(65536-45872)%256; // EA=1; //开总中断 ET0=1; //开定时器0中断 TR0=1; //启动定时器0 while(1); //程序停在这里等待中断发生 }
void T0_time() interrupt 1 { TH0=(65536-45872)/256; //重装初值 TL0=(65536-45872)%256; num++; //num每加1次判断是否到达20次 if(num==20) //如果到了20次,说明1秒时间到 { num=0; //把num清0重新计20次 led1=~led1; //让发光管状态取反 } }
分析:进入主程序后,首先是对定时器和中断有关的寄存器初始化,我们按照上面讲到的通常初始化过程来操作。定时50ms,初值为45872.启动定时器后,主程序停在while(1)处,中断是如何执行呢?一旦开启定时器,定时器便开始计数,当计数溢出时,自动进入中断服务程序。执行完中断服务程序,回到原来处继续执行,也就是继续等待。 用定时器0的方式1实现第1个发光二极管以200ms间隔闪烁。用定时器1的方式1实现数码管前两位59s循环计时。 #include #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; sbit wela=P2^7; sbit led1=P1^0; uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void display(uchar,uchar); uchar num,num1,num2,shi,ge; void main() { TMOD=0x11; //定时器0和1工作方式 TH0=(65536-45872)/256; //装初值 TL0=(65536-45872)%256; TH1=(65536-45872)/256; //装初值 TL1=(65536-45872)%256; EA=1; //开总中断 ET0=1; //开定时器0中断 ET1=1; //开定时器1中断 TR0=1; //启动定时器0 TR1=1; //启动定时器1 while(1) { display(shi,ge); } }
void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送段选数据 dula=0; P0=0xff; //送位选数据前关闭所有显示,防止打开位选锁存时 //原来段选数据通过位选锁存器造成混乱 wela=1; P0=0xfe; //送位选数据 wela=0; delayms(5); //延时
dula=1; P0=table[ge]; dula=0; P0=0xff; wela=1; P0=0xfd; wela=0; delayms(5); }
void delayms(uint xms) { uint i,j; for(i=xms;i>0;i--) for(j=110;j>0;j--); }
void T0_time() interrupt 1 { TH0=(65536-45872)/256; //重装初值 TL0=(65536-45872)%256; num1++; if(num1==4) //200ms { num1=0; led1=~led1; } }
void T1_time() interrupt 3 { TH1=(65536-45872)/256; TL1=(65536-45872)%256; num2++; if(num2==20) //1s { num2=0; num++; if(num==60) //这个数送显,到60后归0 num=0; shi=num/10; ge=num%10; } } 本例用了2个中断函数,进入哪个中断,是靠interrupt后面的序号决定。
|
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |